#include <iostream>
#include <vector>
#include <string>
#include <unistd.h>
#include <sys/wait.h>
#include "Task.hpp"

class Channel
{
public:
    Channel(int fd, int pid) : _fd(fd), _pid(pid)
    {
        _name = "Channel fd: " + std::to_string(fd) + " pid:" + std::to_string(pid);
    }
    
    void Send(int taskcode)
    {
        write(_fd,&taskcode,sizeof(taskcode));
    }
    void Close()
    {
        close(_fd);
    }
    void Wait()
    {
        int n = -1;
        waitpid(_pid,&n,0);
        (void)n;
    }

    int fd(){return _fd;}
    int pid(){return _pid;}
private:
    int _fd;
    int _pid;
    std::string _name;
};

class ChannelManager
{
public:
    void InsertChannel(int fd, int pid)
    {
        
        _cm.emplace_back(fd, pid);
    }
    Channel& Select()
    {
        _next += 1;
        _next %= _cm.size();
        return _cm[_next];
    }
    void CloseAll()
    {
        for(auto& au : _cm)
        {
            au.Close();
        }
    }
    void WaitAll()
    {
        for(auto& au : _cm)
        {
            au.Wait();
        }
    }
private:
    std::vector<Channel> _cm;
    int _next = 0;
};

const int channelNum = 5;

class ProcessPool
{
public:
    void Work(int fd, int pid)
    {
        while (true)
        {
            int code = 0;
            int cnt = read(fd, &code, sizeof(code));
            if (cnt > 0)
            {
                if(sizeof(cnt) != sizeof(code))
                {
                    continue;
                }
                //根据任务码执行任务
                _tm.Execute(code);
            }
            else if (cnt == 0)
            {
                std::cout << "子进程退出" << std::endl;
                break;
            }
            else
            {
                std::cout << "读取错误,退出" << std::endl;
                break;
            }
        }
    }
    bool Start()
    {
        _tm.Register(); //否者会引发浮点数错误
        for (int i = 0; i < channelNum; i++)
        {
            int arr[2] = {0};
            int p = pipe(arr);
            if (p < 0)
            {
                return false;
            }
            int ret = fork();
            if (ret == 0)
            {
                close(arr[1]);
                Work(arr[0], ret);
                close(arr[0]);
            }
            else if (ret > 0)
            {
                close(arr[0]);
                _cm.InsertChannel(arr[1], ret);
                //close(arr[1]);  //这样会导致父进程无法写入管道了
            }
            else
            {
                return false;
            }
        }
        return true;
    }

    void Run()
    {
        //从任务列表里选择一个任务
        int code = _tm.Code();
        //选取一个信道
        Channel c = _cm.Select();
        //发送信号
        c.Send(code);
    }
    void Clear()
    {
        _cm.CloseAll();
        _cm.WaitAll();
    }
private:
    ChannelManager _cm;
    TaskManager _tm;
};